#include <iostream>
#include <pthread.h>
#include <cstdio>
#include <vector>
#include <sys/types.h>
#include <unistd.h>
#include <cstring>
#include <queue>

pthread_cond_t c_cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t p_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

template <class T>
class market
{
public:
    market(std::queue<T> *q) // 使用缺省参数,调用queue的默认构造
        : que_(q)
    {}
    T pop()
    {
        usleep(200000); //期望生产者出了一批货后再去取
        pthread_mutex_lock(&mutex);
        if(que_->size() == 0)
        {
            pthread_cond_signal(&p_cond); //通知生产者已经没货了,唤醒生产者
            pthread_cond_wait(&c_cond, &mutex); //此时消费者被休眠,等待生产者通知来货
        }
        T data = que_->front();
        que_->pop();
        std::cout << "消费者本次获得了数据: " << data << std::endl; 
        pthread_mutex_unlock(&mutex);
        return data;
    }
    void push(T& data)
    {
        usleep(25000);
        pthread_mutex_lock(&mutex);
        if(que_->size() == high_water)
        {
            pthread_cond_wait(&p_cond, &mutex); //此时将生产者休眠,等待消费者取完货
            // pthread_mutex_lock(&mutex);
            //当执行到这条语句时,说明消费者已经将货物全部拿完
            while(que_->size() != low_water)
            {
                std::cout << "生产者生产了: " << data << std::endl;
                que_->push(data++);
            }
            //执行到此处说明货物上最起码有10个货
            pthread_cond_signal(&c_cond);//唤醒消费者
            pthread_mutex_unlock(&mutex);
            return;
        }
        
        que_->push(data);
        std::cout << "生产者生产了: " << data << std::endl;
        if(que_->size() == low_water)
        {
            pthread_cond_signal(&c_cond);
        }
        pthread_mutex_unlock(&mutex);
    }

private:
    std::queue<T> *que_;
    int low_water = 10;  // 超市里的货从0时,消费者会挂起,直到开始生产到10之后才唤醒消费者
    int high_water = 30; // 大于30时让生产者歇逼
};

template <class T>
class threadData
{
public:
    threadData(int num, market<T> *mk)
        : mk_(mk)
    {
        name_ = "mythread->" + std::to_string(num);
    }

    std::string name_;
    market<T> *mk_; // 每个线程的market都是同一份
};

void *custome(void *args)
{
    threadData<int> *custom = static_cast<threadData<int> *>(args);
    while(true)
    {
        int data = custom->mk_->pop();
    }

}

void *product(void *args)
{
    threadData<int> *product = static_cast<threadData<int> *>(args);
    int i = 1;
    while(i)
    {
        product->mk_->push(i);
        i++;
    }
}

int main()
{
    std::queue<int> myque;//需要让两个角色都使用
    market<int> *mym = new market<int>(&myque);
    pthread_t ctip;   // 消费者
    pthread_t ptip;   // 生产者
    threadData<int> *consumer = new threadData<int>(0, mym);  // 方便代码先传个0,代表消费者
    threadData<int> *producter = new threadData<int>(1, mym); // 方便代码先传个1,代表生产者
    int c = pthread_create(&ctip, nullptr, custome, (void *)consumer);
    int p = pthread_create(&ctip, nullptr, product, (void *)producter);
    // std::cout << c << p << std::endl;
    sleep(100000);
    return 0;
}